<?php
namespace payClass\pay;

/**
 * 商户配置
 */
class Config
{

	// 当前文件夹名
	public static $folder;
	// 商户号
    public static $merchant = '1010';
    // 密钥
    public static $key      = 'nLT8AqI9RqvTjj2S';
    // 同步回调（通知）地址
    public static $merUrl;
    // 异步回调（通知）地址
     // public static $notifyUrl;
    public static $notifyUrl = 'https://www.baidu.com';
    // 提交地址
    public static $api      = 'https://pay.fengche3.com/';

	public function __construct()
	{
		self::$folder    = substr(__DIR__, strrpos(__DIR__, '\\')+1);

		self::$merUrl    = 'http://'.$_SERVER['HTTP_HOST'];

		// self::$notifyUrl = self::$merUrl . DIRECTORY_SEPARATOR . 'payClass' . DIRECTORY_SEPARATOR . self::$folder . DIRECTORY_SEPARATOR . 'sycNotice.php';
	}

	public static function addOrder(array $data)
    {
        //bid 商户号。必填项。
        $order['bid']        = self::$merchant;
        //money 订单金额：number，必须大于0。必填项。
        $order['money']      = number_format((float) $data['money'], 2, '.', '');
        //order_sn 订单号：数字或字母组成。必填项。
        $order['order_sn']   = !empty($data['order_sn']) ? $data['order_sn'] : '';
        //notify_url 异步通知地址。必填项。
        $order['notify_url'] = self::$notifyUrl;
        //pay_type string 支付类型：微信扫码: wxpay_qrcode, 微信转账: wxpay_trans, 支付宝扫码: alipay_qrcode, 支付宝转账: alipay_trans
        $order['pay_type']   = !empty($data['pay_type']) ? $data['pay_type'] : '';
        //sign 签名 MD5(
        //商户key + "|" +
        //商户号 + "|" +
        //money + "|" +
        //order_sn + "|" +
        //notify_url)
        //必须按此顺序
        $order['sign'] = md5(
            self::$key . '|' .
            self::$merchant . '|' .
            $order['money'] . '|' .
            $order['order_sn'] . '|' .
            $order['notify_url']
        );
        //下单请求
        // $result = self::curl(self::$api.'api/index', $order);
        $result = self::setHttpRequest(self::$api.'api/index', $order, 'POST', ['Content-Type: multipart/form-data']);

        try {

            $content = json_decode($result, true);

            if(empty($content)) {

                throw new Exception('下单失败');

            }

            if($content['code'] != 100) {

                throw new Exception($content['msg'], $content['code']);

            }

            return $content;

        } catch (Exception $e) {

            return ['code' => $e->getCode(), 'msg' => $e->getMessage()];

        }
	}

    /**
     * 查询订单
     * @param string $order_sn
     * @return array|mixed
    */
    public static function query($order_sn)
    {
        //bid 商户号。必填项。
        $order['bid'] = self::$merchant;
        //order_sn 订单号：数字或字母组成。必填项。
        $order['order_sn'] = $order_sn;
        //sign 签名 MD5(商户key+ "|" + 商户号 + "|" + order_sn)
        //必须按此顺序
        $order['sign'] = md5(
            self::$key . '|' .
            self::$merchant . '|' .
            $order['order_sn']
        );
        //下单请求
        $result = self::curl(self::$api.'api/detail', $order);

        try {

            $content = json_decode($result, true);

            if(empty($content)) {

                throw new Exception('查询失败');

            }

            if($content['code'] != 100) {

                throw new Exception('查询失败:'.$content['msg'], $content['code']);

            }

            return $content;

        } catch (Exception $e) {

            return ['code' => $e->getCode(), 'msg' => $e->getMessage()];

        }
    }

    /**
     * 处理异步通知
     * @param $data
     * @return mixed
    */
    public static function notify($data)
    {
        /**
         * $data 返回数据格式：
         * bid 商户号：number,
         * pay_time 支付时间：number, 10位数时间戳,
         * money 订单金额：number,
         * pay_money 实际支付金额：number,
         * order_sn 商户订单号：string,
         * sys_order_sn 平台订单号：string,
         * sign MD5签名：string,
        */
        try {

            if(empty($data) || !is_array($data)) {

                throw new Exception('数据为空或数据参数错误');

            }

            if(
                empty($data['sign']) ||
                empty($data['pay_time']) ||
                empty($data['money']) ||
                empty($data['pay_money']) ||
                empty($data['order_sn']) ||
                empty($data['sys_order_sn'])
            ) {

                throw new Exception('参数错误');

            }
            //sign 验签
            //MD5(
            //商户key+ "|" +
            //pay_time + "|" +
            //money + "|" +
            //pay_money + "|" +
            //order_sn + "|" +
            //sys_order_sn
            //) 按此顺序验签
            //必须按此顺序
            $data['money']     = number_format($data['money'], 2, '.', '');

            $data['pay_money'] = number_format($data['pay_money'], 2, '.', '');

            $sign = md5(
                self::$key . '|' .
                $data['pay_time'] . '|' .
                $data['money'] . '|' .
                $data['pay_money'] . '|' .
                $data['order_sn'] . '|' .
                $data['sys_order_sn']
            );

            if($sign != $data['sign']) {

                throw new Exception('验签失败');

            }
            /*
            //bid 商户号
            $notify['bid'] = $data['bid'];
            //pay_time 支付时间
            $notify['pay_time'] = $data['pay_money'];
            //money 订单金额
            $notify['money'] = $data['money'];
            //money 实际支付金额
            $notify['pay_money'] = $data['pay_money'];
            //order_sn 商户订单号
            $notify['order_sn'] = $data['order_sn'];
            //sys_order_sn 平台订单号
            $notify['sys_order_sn'] = $data['sys_order_sn'];
            */
            //开始更新订单
            self::logs($data, '_notify');
            // 结束更新订单
            //TODO 返回成功状态关键词 success
            exit('success');

        } catch (Exception $e) {

            self::logs(['data' => $data, 'code' => $e->getCode(), 'msg' => $e->getMessage()], '_notify');

        }

        exit('fail');
    }

    /**
    * 查询商户配置
    * @return array|mixed
    */
    public static function getConfig()
    {
        //bid 商户号。必填项。
        $order['bid'] = self::$merchant;
        //time 当前时间戳10位数。必填项。
        $order['time'] = time();
        //sign 签名 MD5(商户key+ "|" + 商户号 + "|" + time)
        //必须按此顺序
        $order['sign'] = md5(
            self::$key . '|' .
            self::$merchant . '|' .
            $order['time']
        );
        //下单请求
        $result = self::curl(self::$api.'api/config', $order);

        try {

            $content = json_decode($result, true);

            if(empty($content)) {

                throw new Exception('查询失败');

            }

            if($content['code'] != 100) {

                throw new Exception('查询失败:'.$content['msg'], $content['code']);

            }

            return $content;

        } catch (Exception $e) {

            return ['code' => $e->getCode(), 'msg' => $e->getMessage()];

        }
    }

    /**
    * 请求
    * @param string $url
    * @param array $post
    * @return mixed
    */
    public static function curl($url, array $post)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);

        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);

        curl_setopt($ch, CURLOPT_HEADER, 0);

        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);

        curl_setopt($ch, CURLOPT_TIMEOUT, 3);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        curl_setopt($ch, CURLOPT_POST, true);

        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

        if (preg_match('/^https:\/\//i', $url)) {

            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // https请求 不验证证书和hosts

            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 不从证书中检查SSL加密算法是否存在

        }

        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

        curl_setopt($ch, CURLOPT_MAXREDIRS, 2);

        curl_setopt($ch, CURLINFO_HEADER_OUT, true);

        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);

        $response = curl_exec($ch);

        $request_info = curl_getinfo($ch);

        $http_code = $request_info['http_code'];

        self::logs($response);

        if ($http_code == 200) {

            curl_close($ch);

            return $response;

        }
        if (curl_errno($ch)) {

            self::logs(['error' => $url . ' 请求失败 ' . curl_error($ch), 'info' => $request_info]);

            curl_close($ch);

            return false;

        }

        if ($http_code != 200) {

            self::logs(['error' => $url . ' 请求失败,状态:' . $http_code, 'info' => $request_info]);

            curl_close($ch);

            return $response;

        }

        curl_close($ch);

        return $request_info;
    }

    /**
    * 记录日志
    * @param null $log
    * @param string $fn
    */
    public static function logs($log = null, $fn = '')
    {
        $path = __DIR__.'/logs/' . date('Ym/', time());

        if (!is_dir($path)) {

            mkdir($path, 0777, true);

        }

        $name = $path . date('Ymd', time()) . $fn . '.log';

        $content = '';

        if (file_exists($name)) {

            $content = file_get_contents($name);

        }

        $content .= date('Y-m-d H:i:s', time()) . "\n" . var_export($log, true) . "\n------------------\n";

        file_put_contents($name, $content);
    }

    public function output($str)
    {

        header('Content-type: application/json; charset=utf-8');

        echo(json_encode($str));

        exit;
    }

	//发送请求
	public static function setHttpRequest($url, $params = array(), $method = 'POST', $headers = '')
	{
        $ci = curl_init();

        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 30);

        curl_setopt($ci, CURLOPT_TIMEOUT, 30);

        curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method);

        curl_setopt($ci, CURLOPT_URL, $url);

        curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);

        curl_setopt($ci, CURLOPT_HEADER, FALSE);

		curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查

		curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在

        if ($headers != '') {

            curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);

        } else {

            curl_setopt($ci, CURLOPT_HTTPHEADER, array('Content-type: application/json'));

        }

        switch (strtoupper($method)) {
            case 'POST':

                curl_setopt($ci, CURLOPT_POST, TRUE);

                curl_setopt($ci, CURLOPT_POSTFIELDS, $params);

                break;

            case 'PUT':

                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'PUT');

                curl_setopt($ci, CURLOPT_POSTFIELDS, $params);

                break;

            case 'PATCH':

                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'PATCH');

                curl_setopt($ci, CURLOPT_POSTFIELDS, $params);

                break;

            case 'DELETE':

                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');

                curl_setopt($ci, CURLOPT_POSTFIELDS, $params);

                break;

            default:

                curl_setopt($ci, CURLOPT_HTTPGET, TRUE);

                break;
        }

        $response = curl_exec($ci);

        $httpCode = curl_getinfo($ci);

        curl_close($ci);

        return $response;
    }
}